package barrier;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author roei
 * "Barrier" written using regular lock.
 * (Mutex barrier)
 */
public class LockBarrier implements Barrier {
  final ReentrantLock _lock = new ReentrantLock();
  final Condition _cond = _lock.newCondition();
  int _size;
  int _count;
  private boolean _sense;
  private ThreadLocal<Boolean> _threadSense;
 
  /**
   * C'tor
   * @param n Number of threads. 
   */
  public LockBarrier(int n) {
    _count = n;
    _size = n;
    _sense = false;
    _threadSense = new ThreadLocal<Boolean>() {
      @Override
      protected Boolean initialValue() { return !_sense; };
    };

  }
 
  @Override
  public void await() {
    boolean mySense = _threadSense.get();
    //final ReentrantLock lock = _lock; 
    _lock.lock();
    try {
      int position = --_count;
      if (position == 0) { // If I'm last
        _count = _size;   // reset for next use
        _sense = mySense; // reverse sense
        _cond.signalAll();
//        lock.unlock();
      } else {       // otherwise spin
//        lock.unlock();
        while (mySense != _sense) {
          _cond.await();
        } // busy-wait
      }
    } catch (Throwable t) {
      System.out.println("cought throwable: " +t );
    } finally {
      if (_lock.isLocked())
        _lock.unlock();
//      if (lock.isLocked())
//        lock.unlock();
      
    }
  }

}